import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.*;
import java.awt.image.*;
import java.io.FileInputStream;
import java.util.*;
import javax.imageio.*;
import javax.swing.*;

/**
 * @author Mihai Moraru
 */
public class ArduinoPin extends JComponent implements MouseListener {
	public ArduinoPin(double x, double y)
	{
		loadImages();
		this.posX = x;
		this.posY = y;
		this.setOpaque(false); // we don't paint everything -> transparency
	}

	/* Required by MouseListener interface */
	public void mouseClicked(MouseEvent e)
	{
		System.out.println("click!\n");
		if(mode != ArduinoCore.INPUT)
			return;
		if(e.getButton() == MouseEvent.BUTTON1)
			setVoltage(ArduinoCore.V_HIGH);
		else if(e.getButton() == MouseEvent.BUTTON3)
			setVoltage(ArduinoCore.V_LOW);
	}

	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
	/* end MouseListener */

	public Dimension getPreferredSize()
	{
		return new Dimension(prefW, prefH);
	}

	public double getPreferredX()
	{
		return posX;
	}

	public double getPreferredY()
	{
		return posY;
	}

	protected void paintComponent(Graphics g)
	{
		BufferedImage image;
		if(voltage <= ArduinoCore.V_LOW)
			image = imageList.get("pics/led_off.png");
		else if(voltage >= ArduinoCore.V_HIGH)
			image = imageList.get("pics/led_on.png");
		else { // blend
			int i = (int)((ArduinoCore.V_HIGH-ArduinoCore.V_LOW)/(voltage-ArduinoCore.V_LOW));
			System.err.println("Blend "+i);
			image = imageList.get("pics/led_off.png");
		}
		int w = image.getWidth();
		int h = image.getHeight();
		int W = this.getWidth();
		int H = this.getHeight();
		g.drawImage(image, 0, 0, W, H, 0, 0, w, h, null);
	}

	private void loadImages()
	{
		if(imageList != null)
			return; // imageList is already populated
		String nameList[] = {
			"pics/led_off.png",
			"pics/led_on.png"
		};
		imageList = new Hashtable<String, BufferedImage>(32);
		BufferedImage image;
		for(String name:nameList) {
			System.err.println("Loading image '"+name+"'...");
			try {
				//image = ImageIO.read(this.getClass().getResource(name)); 
				image = ImageIO.read(new FileInputStream(name));
				imageList.put(name, image);
			} catch(Exception e) {
				System.err.println("Image '"+name+"' could not be read!");
				System.exit(1);
			}
		}
		System.err.println(imageList);
	}

	/* Arduino API */
	public void pinMode(int val)
	{
		if(val != ArduinoCore.INPUT && val != ArduinoCore.OUTPUT)
			return;
		mode = val;
	}

	public int digitalRead()
	{
		if(mode != ArduinoCore.INPUT)
			return 0;
		//System.out.println("digitalRead: voltage "+voltage);
		if(voltage < 2.5)
			return ArduinoCore.LOW;
		return ArduinoCore.HIGH;
	}

	public void digitalWrite(int val)
	{
		//System.out.println("ArduinoPin.digitalWrite("+val+")");
		if(val != ArduinoCore.HIGH && val != ArduinoCore.LOW)
			return;
		if(val == ArduinoCore.HIGH) {
			if(mode == ArduinoCore.OUTPUT)
				voltage = ArduinoCore.V_HIGH;
			/* turn on pullup resistor enough to dimly light up a LED */
			else voltage = ArduinoCore.V_LOW+(ArduinoCore.V_HIGH-ArduinoCore.V_LOW)*1/10;
		} else voltage = ArduinoCore.V_LOW;
		this.repaint();
	}

	private void setVoltage(double val)
	{
		voltage = val;
		this.repaint();
	}

	public int analogRead() { return 0; }
	public void analogWrite(int val) {}

	/* Fields */
	protected int mode = ArduinoCore.INPUT;
	protected double voltage = ArduinoCore.V_LOW;

	private double posX; // relative  to canvas width
	private double posY; // relative to canvas height
	private int prefW = 40;
	private int prefH = 40;

	/* Static fields */
	private static Hashtable<String, BufferedImage> imageList;
}
